﻿using System;

using System.Collections.Generic;
using System.Text;

namespace Silvermoon.Windows
{

    /// <summary>
    /// Implements a weak event listener that allows the owner to be garbage collected if its only remaining link is an event handler.
    /// </summary>
    public class WeakEventListener
    {
        private WeakReference sender;
        private WeakReference listener;

        /// <summary>
        /// Creates a new event handler.
        /// </summary>
        /// <param name="sender">Sender which created the event.</param>
        /// <param name="listener">Listener which listens for events.</param>
        /// <param name="action">Method to be executed when the event raises. IMPORTANT: this must be a static method!</param>
        /// <param name="detach">Method that removes the event handler from the sender. IMPORTANT: this must be a static method!</param>
        public WeakEventListener(object sender, object listener, EventHandler action, EventHandler detach)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (detach == null) throw new ArgumentNullException("detach");
            this.sender = new WeakReference(sender);
            this.listener = new WeakReference(listener);
            this.Action = action;
            this.Detach = detach;
        }

        ~WeakEventListener()
        {
            sender.Target = null;
            listener.Target = null;
            sender = null;
            listener = null;
        }


        protected EventHandler Action { get; set; }
        protected EventHandler Detach { get; set; }

        public void OnEvent(object sender, EventArgs e)
        {
            if (!listener.IsAlive)
            {
                OnDetach();
            }
            else
            {
                Action(listener.Target, e);
            }
        }

        private void OnDetach()
        {
            if (listener.IsAlive && sender.IsAlive)
            {
                Detach(listener.Target, EventArgs.Empty);
            }
            listener.Target = null;
            sender.Target = null;
        }
    }
}
